package org.jeecg.modules.system.aspect;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.ArrayUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.Dict;
import org.jeecg.modules.system.mapper.SysDictItemMapper;
import org.jeecg.modules.system.service.ISysDictService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author lixingxing
 */
@Component
@Aspect
@Slf4j
public class DictAspect {

    @Autowired
    private ISysDictService dictService;

    @Autowired
    private SysDictItemMapper sysDictItemMapper;

    ObjectMapper mapper = new ObjectMapper();

    @Pointcut("execution(public org.jeecg.common.api.vo.Result org.jeecg.modules..*.*Controller.*(..)) || execution(public org.jeecg.common.api.vo.Result cn.com.hhrcw..*.*Controller.*(..))")
    public void point() {

    }

    @Around("point()")
    public Result run(ProceedingJoinPoint join) throws Throwable {
        Object[] args = join.getArgs();
        Result result = (Result) join.proceed(args);
        if (result == null) {
            return new Result();
        }
        Object obj = result.getResult();
        if (obj == null) {
            return result;
        }
        //分页数据注入
        if (obj instanceof IPage) {
            IPage page = (IPage) obj;
            List list = page.getRecords();
            for (int i = 0; i < list.size(); i++) {
                list.set(i, loop(list.get(i)));
            }
            //集合数据注入
        } else if (obj instanceof List) {
            List list = (List) obj;
            for (int i = 0; i < list.size(); i++) {
                list.set(i, loop(list.get(i)));
            }
            //VO数据注入
        } else if (obj instanceof Map) {
            Map map = (Map) obj;
            Set<Map.Entry<String, Object>> set = map.entrySet();
            Iterator<Map.Entry<String, Object>> iterator = set.iterator();
            while (iterator.hasNext()) {
                Map.Entry<String, Object> entry = iterator.next();
                Object value = entry.getValue();
                if (value instanceof List) {
                    List list = (List) value;
                    for (int i = 0; i < list.size(); i++) {
                        list.set(i, loop(list.get(i)));
                    }
                } else {
                    entry.setValue(loop(value));
                }
            }
        } else {
            result.setResult(loop(obj));
        }
        log.debug("{}", JSON.toJSONString(result));
        return result;
    }

    /**
     * 返回结果集字典数据注入
     *
     * @param obj
     * @return
     * @throws JsonProcessingException
     * @throws IllegalAccessException
     */
    public Object loop(Object obj) throws JsonProcessingException, IllegalAccessException {
        if (obj == null) {
            return obj;
        }
        Field[] fields = ReflectUtil.getFields(obj.getClass());
        String json = mapper.writeValueAsString(obj);
        if (!JSONUtil.isJson(json)) {
            return obj;
        }
        JSONObject jsonObj = JSON.parseObject(json);

        for (Field field : fields) {
            Object fieldValue = ReflectUtil.getFieldValue(obj, field);
            if (fieldValue == null) {
                continue;
            }
            //List类型属性
            if (fieldValue instanceof List) {
                Object listObj = field.get(obj);
                if (listObj == null) {
                    continue;
                }
                //获取泛型类型
                Type genericType = field.getGenericType();
                if (genericType instanceof ParameterizedType) {
                    ParameterizedType pt = (ParameterizedType) genericType;
                    //泛型类型
                    Class<?> actualTypeArgument = (Class<?>) pt.getActualTypeArguments()[0];
                    //泛型类型为VO结尾
                    if (actualTypeArgument.getName().endsWith("VO")) {
                        List list = (List) listObj;
                        List newList = Lists.newArrayListWithCapacity(list.size());
                        for (Object data : list) {
                            Object o = loop(data);
                            newList.add(o);
                        }
                        jsonObj.put(field.getName(), newList);
                    }
                }
            }
            if (fieldValue.getClass().getName().endsWith("VO")) {
                Object o = loop(field.get(obj));
                jsonObj.put(field.getName(), o);
            } else {
                String key = jsonObj.getString(field.getName());
                if (StrUtil.isBlank(key)) {
                    key = "";
                }
                if (field.isAnnotationPresent(Dict.class)) {
                    Dict dict = field.getAnnotation(Dict.class);
                    String[] keys = key.split(dict.separator());
                    if (ArrayUtils.isEmpty(dict.replace())) {

                        if (ArrayUtils.isNotEmpty(dict.dicTexts())) {
                            // 2021年5月25日10:13:01 朱修轩加  支持翻译多字段
                            String[] strings = dict.dicTexts();
                            for (int i = 0; i < strings.length; i++) {
                                strings[i] = StrUtil.toUnderlineCase(strings[i]);
                            }
                            String join = String.join(",", strings);
                            Map<String, Object> objectMap = sysDictItemMapper.selectTable(dict.dictTable(), join, StrUtil.toUnderlineCase(dict.dicCode()), key);

                            if (null != objectMap) {
                                for (Map.Entry<String, Object> entry : objectMap.entrySet()) {
                                    jsonObj.put(field.getName() + "_" + StrUtil.toCamelCase(entry.getKey()), entry.getValue());
                                }
                            }

                        } else {
                            Object val = dict.multiple() ? keys : key;
                            String value = translateDictValue(StrUtil.toUnderlineCase(dict.dicCode()), StrUtil.toUnderlineCase(dict.dicText()), dict.dictTable(), val, dict.multiple());
                            jsonObj.put(field.getName() + "_dictText", value);
                            if (!dict.keep()) {
                                jsonObj.remove(field.getName());
                            }
                        }

                    } else {
                        //属性值替换
                        String[] replace = dict.replace();
                        StringBuilder builder = new StringBuilder();
                        Map<String, String> entry = Stream.of(replace).map(e -> e.split("_")).collect(Collectors.toMap(e -> e[0], e -> e[1]));
                        if (dict.multiple()) {
                            for (String k : keys) {
                                builder.append("," + entry.get(k));
                            }
                        } else {
                            builder.append("," + entry.get(key));
                        }
                        if (!dict.keep()) {
                            jsonObj.remove(field.getName());
                        }
                        String text = StrUtil.equals(builder.substring(1), "null") ? null : builder.substring(1);
                        jsonObj.put(field.getName() + "_dictText", text);
                    }

                } else {
                    Object o = jsonObj.get(field.getName());
                    if (o instanceof String) {
                        key = key.replaceAll("(@ent|@admin)", "");
                        jsonObj.put(field.getName(), key);
                    }
                }
            }
        }
        return jsonObj;
    }

    /**
     * 翻译字典文本
     *
     * @param code
     * @param text
     * @param table
     * @param key
     * @return
     */
    private String translateDictValue(String code, String text, String table, Object key, boolean multiple) {
        StringBuffer textValue = new StringBuffer();
        String tmpValue = null;
        log.debug(" 字典 key : " + key);
        if (!StringUtils.isEmpty(table)) {
            log.debug("--DictAspect------dicTable=" + table + " ,dicText= " + text + " ,dicCode=" + code);
            if (multiple) {
                List<String> list = sysDictItemMapper.selectTableFieldMultiple(table, text, code, (String[]) key);
                tmpValue = StrUtil.join(",", list.toArray());
            } else {
                tmpValue = sysDictItemMapper.selectTableField(table, text, code, (String) key);
            }
        } else if (StrUtil.isNotBlank(code)) {
            tmpValue = dictService.queryDictTextByKey(code, Convert.toStr(key));
        }
        if (tmpValue != null) {
            if (!"".equals(textValue.toString())) {
                textValue.append(",");
            }
            textValue.append(tmpValue);
        }

        return textValue.toString();
    }
}
